package com.example.leo.mycharmingstudent.a0904;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.leo.mycharmingstudent.R;
import com.example.leo.mycharmingstudent.a0904.generics.Pair;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class HandlerActivity extends AppCompatActivity {

    private TextView tvFirst;
    private TextView tvSecond;
    private Handler mHandler = new Handler();

    /**
     * 不要在同一个类或者Activity里面创建两个Handler
     */
    private Handler mSecondHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            /*
            HandlerActivity.this对象已经被Handler持有了。
            因为可以直接访问到HandlerActivity.this对象。
            如果handler还有未完成的任务，哪怕HandlerActivity.this已经执行了finish方法，
            HandlerActivity.this对象不会被虚拟机回收。
             */
            /*
             注意：switch语句中，case需要和break搭配
             如果确定不需要break，可以不要break语句
             为啥case需要和break搭配？
             因为只要匹配到一个case，没有break语句，
             后面多有的case中的代码，都会被执行
             */
            switch (msg.what) {
                case 1:
                    String format = String.format("收到信息了:%d", msg.what);
                    Toast.makeText(HandlerActivity.this, format, Toast.LENGTH_LONG).show();
                    break;
                case 2:
                    String format2 = String.format("收到信息了:%d %s",
                            msg.what, msg.obj);
                    Toast.makeText(HandlerActivity.this,
                            format2,
                            Toast.LENGTH_LONG).show();
                    break;
                case 4:
                    int countDown = (int) msg.obj;
                    tvCountDown.setText(String.valueOf(countDown));

                    if (countDown > 0) {
                        //还需要延迟一秒再发送一条消息
                        Message obtain = Message.obtain();
                        obtain.what = 4;
                        obtain.obj = --countDown;
                        sendMessageDelayed(obtain, 1000);
                    } else {
                        Toast.makeText(HandlerActivity.this,
                                "倒计时结束，醒醒",
                                Toast.LENGTH_LONG).show();
                        //使控件点击事件生效
                        tvCountDown.setEnabled(true);
                    }
                    break;
                default:
                    Toast.makeText(HandlerActivity.this,
                            "what are you 弄啥咧",
                            Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };
    private TextView tvCountDown;

    private final static int COUNT_DOWN_SECONDS = 5;
    private Handler mMyhandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        findViews();
        initData();
        initEvent();
    }

    private void findViews() {
        tvFirst = findViewById(R.id.tv_first_line_activity_handler);
        tvSecond = findViewById(R.id.tv_second_line_activity_handler);

        tvCountDown = findViewById(R.id.tv_count_down_activity_handler);
    }

    private void initData() {
//        mHandler = new Handler();
        //立即发送任务  执行
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                tvFirst.setText("第一行文本");
            }
        });
        /*
        延迟3秒 发送任务  执行
        具体延迟多少，postDelayed方法第二个参数决定的
        java中和时间相关的单位，默认都是毫秒  1秒（s） = 1000毫秒（ms）
         */
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                tvSecond.setText("第二行文本");
            }
        }, 3_000);

        /**
         * Android中所有创建的线程，都是子线程
         */
        new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();

        //发送空消息
//        mSecondHandler.sendEmptyMessage(1);
        //发送消息
        Message obtain = Message.obtain();
        obtain.what = 2;
        /*
        向上转型  安全
        所有的类都默认直接或间接继承Object，也就是说，
        所有类型都可以用Object定义。
        Object object = "string";
        Object object1 = 1;
        Object object2 = 'a';
        Object object3 = this;
         */
        obtain.obj = "sendMessage";
//        mSecondHandler.sendMessage(obtain);
//        mSecondHandler.sendEmptyMessage(3);

        mMyhandler = new MyHandler(this);
        mMyhandler.sendEmptyMessage(0);

        generics();
    }

    private void generics() {
        Pair<Integer, Activity, Object, Object> first =
                new Pair<Integer, Activity, Object, Object>(2, 9, this);
        Integer f = first.getFirst();
        Integer s = first.getSecond();
        Activity third = first.getThird();

        Pair<String, Integer, Object, Object> second =
                new Pair<String, Integer, Object, Object>("学习", "泛型", 1);
        String firstString = second.getFirst();
        String secondString = second.getSecond();
        Integer thirdString = second.getThird();

        Integer a = second.getA(1);
        String string = second.getA("string");

        //通配符///////////////////////////////////////////
        Collection<Integer> list1 = new ArrayList<Integer>();
        getElement(list1);
        Collection<String> list2 = new ArrayList<String>();
        getElement(list2);
        list1.add(1);
        list1.add(2);

        list2.add("1");
        list2.add("2");

        //此处使用通配符？，此时只能接受数据,不能往该集合中存储数据。
        List<?> list = new ArrayList<>();
//        list.add(1);//报错
        //通配符高级使用，以及通配符？与泛型定义的区别///////////////////////////////////////////
        List<TextView> object1 = new ArrayList<>();
        List<Number> object2 = new ArrayList<>();
        List<View> object3 = new ArrayList<>();
        List<Object> object4 = new ArrayList<>();

        //getElement1方法参数指定的泛型上限是View
        getElement1(object1);
        /*
         * 为什么报错？
         * 指定上限类型是View，View和View的子类都可以，其余类型均不可。
         * Number类型和View类型无关，所以报错。
         */
//        getElement1(object2);//报错
        getElement1(object3);
        /*
         * 为什么报错？
         * 指定上限类型是View，View和View的子类都可以，其余类型均不可。
         * Object是View类型的父类，超出上限，所以报错。
         */
//        getElement1(object4);//报错

        //getElement2方法参数指定的泛型下限是EditText
        getElement2(object1);
        /*
         * 为什么报错？
         * 指定下限类型是EditText，EditText和EditText的父类都可以，其余类型均不可。
         * Number类型和EditText类型无关，所以报错。
         */
//        getElement2(object2);//报错
        getElement2(object3);
        getElement2(object4);
        //注意通配符？和定义泛型T（可以是别的大写字母）的区别//////////////////////////////////////////

        List<?> list09050 = new ArrayList<>();
//        List<T> list09051 = new ArrayList<T>();
         //此处不是要创建泛型类，不是要创建泛型方法，那为什么要声明泛型呢？
        //也就是说，此处要指定具体类型
//        List<此处不是让声明泛型,而是要求指定具体类型> list09051
//                          = new ArrayList<此处不是让声明泛型,而是要求指定具体类型>();


        /*
        此处是声明泛型，
        声明泛型就不能指定具体类型
        通配符？是一个具体类型
        so，此处不可以使用通配符？
         */
        /*public <T extends View> T findViewById(@IdRes int id) {
            return this.getDelegate().findViewById(id);
        }*/
        ///////////////////////////////////////////
    }

    /**
     * 通配符？表示所有类型
     * 用到的关键字是extends
     * 所有类型，都必须是View或者View子类的一种
     * 也就是说，上限确定，是View
     */
    private void getElement1(List<? extends View> viewList){}

    /**
     * 通配符？表示所有类型
     * 用到的关键字是super
     * 所有类型，都必须是EditText或者EditText父类的一种
     * 也就是说，下限确定，是EditText
     */
    private void getElement2(List<? super EditText> editTextList){}

    /*
    重载方法：同名不同参
    现象：
    generics0(List<Integer> integerList)和generics0(List<String> stringList)冲突了
    引出一个问题：为什么冲突了？
    因为泛型擦除。
    泛型擦除，泛型类型信息（List<Integer>当中的Integer和List<String>当中的String）被擦除了。
    泛型类型被擦除了，那么generics0(List<Integer> integerList)和generics0(List<String> stringList)
    方法名和方法参数都一样，这是不允许的。所以报错。
     */
/*    private void generics0(List<Integer> integerList){
        //空实现
    }
    private void generics0(List<String> stringList){
        //非空实现
    }*/

    private void generics0(String string){}

    public static void getElement(Collection<?> coll){}

    private void initEvent() {
        tvCountDown.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //使控件点击事件失效
                tvCountDown.setEnabled(false);
                //开始倒计时
                tvCountDown.setText(String.valueOf(COUNT_DOWN_SECONDS));
                //延迟一秒发送
                Message obtain = Message.obtain();
                obtain.what = 4;
                obtain.obj = COUNT_DOWN_SECONDS - 1;
                mSecondHandler.sendMessageDelayed(obtain, 1000);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
        mSecondHandler.removeCallbacksAndMessages(null);
        mMyhandler.removeCallbacksAndMessages(null);
    }

    private static class MyHandler extends Handler {
        private WeakReference<Activity> mContextReference;

        private MyHandler(Activity context) {
            mContextReference = new WeakReference<Activity>(context);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //演示  静态类不会持有外部类的this对象
            /*Toast.makeText(HandlerActivity.this,
                    "",
                    Toast.LENGTH_LONG).show();*/
            //此处需要注意，context有可能被回收，值是null
            Activity context = mContextReference.get();
            if (context != null) {
                Toast.makeText(context,
                        "static class MyHandler",
                        Toast.LENGTH_LONG).show();
            }
        }
    }
}
